package models

import (
	"errors"
	"fmt"

	"gorm.io/gorm"
)

type SysApi struct {
	ModelBase
	Path        string `json:"path" form:"path" gorm:"comment:api路径"`                 // api路径
	Description string `json:"description" form:"description" gorm:"comment:api中文描述"` // api中文描述
	ApiGroup    string `json:"apiGroup" form:"apiGroup" gorm:"comment:api组"`          // api组
	Method      string `json:"method" form:"method" gorm:"default:POST;comment:方法"`   // 方法:创建POST(默认)|查看GET|更新PUT|删除DELETE
}

func (SysApi) TableName() string {
	return "sys_apis"
}

// 添加api
func CreateApi(api SysApi) (err error) {
	if !errors.Is(db.Where("path = ? AND method = ?", api.Path, api.Method).First(&SysApi{}).Error, gorm.ErrRecordNotFound) {
		return errors.New("存在相同api")
	}
	return db.Create(&api).Error
}

// 删除单个api
// TODO 绑定api到casbin上
func DeleteApi(id int) (err error) {
	var entity SysApi
	err = db.Where("id = ?", id).First(&entity).Error // 根据id查询api记录
	if errors.Is(err, gorm.ErrRecordNotFound) {       // api记录不存在
		return err
	}
	err = db.Delete(&entity).Error
	// if err != nil {
	// 	return err
	// }
	// success := CasbinServiceApp.ClearCasbin(1, entity.Path, entity.Method)
	// if !success {
	// 	return errors.New(entity.Path + ":" + entity.Method + "casbin同步清理失败")
	// }
	// e := CasbinServiceApp.Casbin()
	// err = e.InvalidateCache()
	// if err != nil {
	// 	return err
	// }
	return err
}

// 分页获取api列表
func GetAPIInfoList(api SysApi, page, pageSize int, order string, desc bool) (list interface{}, total int64, err error) {
	limit := pageSize
	offset := pageSize * (page - 1)
	db := db.Model(&SysApi{})
	var apiList []SysApi

	if api.Path != "" {
		db = db.Where("path LIKE ?", "%"+api.Path+"%")
	}

	if api.Description != "" {
		db = db.Where("description LIKE ?", "%"+api.Description+"%")
	}

	if api.Method != "" {
		db = db.Where("method = ?", api.Method)
	}

	if api.ApiGroup != "" {
		db = db.Where("api_group = ?", api.ApiGroup)
	}

	err = db.Count(&total).Error

	if err != nil {
		return apiList, total, err
	} else {
		db = db.Limit(limit).Offset(offset)
		if order != "" {
			var OrderStr string
			// 设置有效排序key 防止sql注入
			// 感谢 Tom4t0 提交漏洞信息
			orderMap := make(map[string]bool, 5)
			orderMap["id"] = true
			orderMap["path"] = true
			orderMap["api_group"] = true
			orderMap["description"] = true
			orderMap["method"] = true
			if orderMap[order] {
				if desc {
					OrderStr = order + " desc"
				} else {
					OrderStr = order
				}
			} else { // didn't matched any order key in `orderMap`
				err = fmt.Errorf("非法的排序字段: %v", order)
				return apiList, total, err
			}

			err = db.Order(OrderStr).Find(&apiList).Error
		} else {
			err = db.Order("api_group").Find(&apiList).Error
		}
	}
	return apiList, total, err
}

// 一次获取全部api数据
func GetAllApis() (apis []SysApi, err error) {
	err = db.Find(&apis).Error
	return
}

// 根据id返回特定api详情
func GetApiById(id int) (api SysApi, err error) {
	err = db.Where("id = ?", id).First(&api).Error
	return
}

// 更新api信息
// 同步casbin的信息
func UpdateApi(api SysApi) (err error) {
	var oldA SysApi
	err = db.Where("id = ?", api.ID).First(&oldA).Error
	if oldA.Path != api.Path || oldA.Method != api.Method {
		if !errors.Is(db.Where("path = ? AND method = ?", api.Path, api.Method).First(&SysApi{}).Error, gorm.ErrRecordNotFound) {
			return errors.New("存在相同api路径")
		}
	}
	// if err != nil {
	// 	return err
	// } else {
	// 	err = CasbinServiceApp.UpdateCasbinApi(oldA.Path, api.Path, oldA.Method, api.Method)
	// 	if err != nil {
	// 		return err
	// 	} else {
	// 		err = global.GVA_DB.Save(&api).Error
	// 	}
	// }
	return db.Save(&api).Error
}

// 根据id数组，批量删除api
func DeleteApisByIds(ids []int) (err error) {
	var apis []SysApi
	err = db.Find(&apis, "id in ?", ids).Delete(&apis).Error
	// if err != nil {
	// 	return err
	// } else {
	// 	for _, sysApi := range apis {
	// 		success := CasbinServiceApp.ClearCasbin(1, sysApi.Path, sysApi.Method)
	// 		if !success {
	// 			return errors.New(sysApi.Path + ":" + sysApi.Method + "casbin同步清理失败")
	// 		}
	// 	}
	// 	e := CasbinServiceApp.Casbin()
	// 	err = e.InvalidateCache()
	// 	if err != nil {
	// 		return err
	// 	}
	// }
	return err
}
